
export default class Matrix{
    //矩阵相乘
    Mul(matrixA,matrixB){
        /* 矩阵相乘 ，结果矩阵的元*/
        function  ProductEntry(i,j,t,matrixA,matrixB){
            let result =0;
            for(let k = 0;k<t;k++)
                result +=matrixA[i][k]*matrixB[k][j];
            return result;
        }
        let [m,t,n] = [matrixA.length,matrixA[0].length,matrixB[0].length];
        if(t != matrixB.length)
            throw  new Error("列行不等");
        let matrix = this.Zero(m);
        for(let i =0;i<m;i++){
            for(let j=0;j<n;j++){
                matrix[i][j] =ProductEntry(i,j,t,matrixA,matrixB);

            }
        }
        return matrix;
    };
    //零矩阵
    Zero(m,n){
        let N = n||m;
        return new Array(m).fill(0).map(arr => new Array(N).fill(0));;
    }
    //矩阵相加
    Add(matrixA,matrixB){
        let [m,n] = [matrixA.length,matrixA[0].length]
        let matrix = this.Empty(m);
        for(let i =0;i<m;i++){
            for(let j=0;j<n;j++){
                matrix[i][j] =  matrixA[i][j]+matrixB[i][j]
            }
        }
        return matrix;
    };

    Empty(m){
        let matrix =[];
        for(let i =0 ;i<m;i++)
            matrix.push([]);
        return matrix;
    }
    //矩阵乘以数字
    MulNum(matrix,num) {
        let [m,n] = [matrix.length,matrix.length]
        let mtrx = this.Empty(m);
        for(let i =0;i<m;i++){
            for(let j=0;j<n;j++){
                mtrx[i][j] =  matrix[i][j]*num;
            }
        }
        return mtrx;
    };

    //单位矩阵
    Eye(n){
        let matrix = this.Zero(n);
        for(let i =0;i<n;i++)
                matrix[i][i]= 1;
        return matrix;
    }

    //求代数余子式
    cofactor(matrix,x,y){
        let [m,n] = [matrix.length,matrix.length];
        let [c_m,c_n,c_i,c_j] = [m-1,n-1,0,0];
        let matrixC =this.Zero(c_m);
        for(let i =0;i<m;i++){
            if(i!=x){
                c_j =0;
                for(let j=0;j<n;j++){
                    if(j!=y){
                        matrixC[c_i][c_j] = matrix[i][j];
                        c_j +=1;
                    }
                }
                c_i +=1;
            }
        }
        return matrixC;
    }

    /*求矩阵对应的行列式  行列式是个数字*/
    Det(square){
        // 方阵约束
        if (square.length !== square[0].length) {
            throw new Error("列行不等");
        }
        // 方阵阶数
        let n = square.length;

        let result = 0;
        if (n > 3) {
            // n 阶
            for (let column = 0; column < n; column++) {
                // 去掉第 0 行第 column 列的矩阵
                let matrix = new Array(n - 1).fill(0).map(arr => new Array(n - 1).fill(0));
                for (let i = 0; i < n - 1; i++) {
                    for (let j = 0; j < n - 1; j++) {
                        if (j < column) {
                            matrix[i][j] = square[i + 1][j];
                        } else {
                            matrix[i][j] = square[i + 1][j + 1];
                        }
                    }
                }
                result += square[0][column] * Math.pow(-1, 0 + column) * this.Det(matrix);
            }
        } else if (n === 3) {
            // 3 阶
            result = square[0][0] * square[1][1] * square[2][2] +
                square[0][1] * square[1][2] * square[2][0] +
                square[0][2] * square[1][0] * square[2][1] -
                square[0][2] * square[1][1] * square[2][0] -
                square[0][1] * square[1][0] * square[2][2] -
                square[0][0] * square[1][2] * square[2][1];
        } else if (n === 2) {
            // 2 阶
            result = square[0][0] * square[1][1] - square[0][1] * square[1][0];
        } else if (n === 1) {
            // 1 阶
            result = square[0][0];
        }
        return result;
    };

    //逆矩阵  by 伴随矩阵
    Inv(matrix){
        let n = matrix.length;
        let DetValue = this.Det(matrix);
        if(DetValue ==0 )
            throw  new Error("无逆矩阵");
        let MAdj =  this.Adjoint(matrix);
        for(let i =0;i<n;i++){
            for(let j=0;j<n;j++){
                MAdj[i][j] =  MAdj[i][j]/DetValue;
            }
        }
        return MAdj;
    };

    //伴随矩阵
    Adjoint(matrix){
        let n = matrix.length;
        let mtrx = this.Zero(n);
        for(let i =0;i<n;i++){
            for(let j=0;j<n;j++){
                mtrx[i][j] =  this.Det(this.cofactor(matrix,i,j))*Math.pow(-1,i+j);
            }
        }
        return this.T(mtrx);
    }

    //矩阵转置
    T(matrix){
        let m = matrix.length;
        let n = matrix[0].length;
        let Tmatrix = this.Zero(n);
        for(let i=0;i<n;i++){
            for(let j=0;j<m;j++){
                Tmatrix[i][j] = matrix[j][i];
            }
        }
        return Tmatrix;
    };

    //矩阵 L U 分解
    LU(matrix){
        // r 代表  的第r 行  i代表列数
        function sumForU(r,i){
            let sum = 0;
            for(let k=0;k<r;k++){
                sum += L[r][k] * U[k][i]
            }
            return sum;
        }

        // r 代表 L 的第r 列   i代表行数
        function  sumForL(r,i) {
            let sum = 0;
            for(let k=0;k<r;k++)
                sum += L[i][k] * U[k][r];
            return sum;
        }

        let n = matrix.length;
        let A= matrix;
        let U =this.Zero(n);
        let L = this.Eye(n);

        /*
        计算U的第r行，L的第r列元素
        U[r][i]=A[r][i]-Σ(k=1  ->  r-1) L[r][k]U[k][i]    (i=r,r+1,...,n)
        L[i][r]=(A[i][r]-Σ(k=1 ->  r-1) L[i][k]U[k][r])/U[r][r]    (i=r+1,r+2,...,n且r≠n)
        */

        for (let r = 0; r < n; r++) {
            for (let i = r; i < n; i++) {
                //U 求行
                U[r][i] = A[r][i] - sumForU(r, i);
                if(i>r)
                    L[i][r] = (A[i][r] - sumForL(r, i)) / U[r][r];
            }
        }

        return { U,L};
    }

    // U 矩阵的逆矩阵
    InvOfU(U){
        let n = U.length;
        let I = this.Zero(n);
        /*
        求矩阵U的逆
        * */
        for (let i=0;i<n;i++)
        {
            I[i][i]=1/U[i][i];//对角元素的值，直接取倒数
            for (let k=i-1;k>=0;k--)
            {
                let s=0;
                for (let j=k+1;j<=i;j++)
                    s=s+U[k][j]*I[j][i];
                //迭代计算，按列倒序依次得到每一个值，
                I[k][i]=-s/U[k][k];
            }
        }
        return I;
    }

    //L 矩阵的逆矩阵
    InvOfL(L){
        let n = L.length;
        let I = this.Zero(n);

        for (let i=0;i<n;i++)
        {
            I[i][i]=1; //对角元素的值，直接取倒数，这里为1
            for (let k=i+1;k<n;k++)
            {
                for (let j=i;j<=k-1;j++)
                    I[k][i]=I[k][i]-L[k][j]*I[j][i];   //迭代计算，按列顺序依次得到每一个值
            }
        }
        return I;
    }

    //矩阵复制
    copy(matrix){
        let n = matrix.length;
        let mtrx = this.Zero(n);
        for(let i=0;i<n;i++){
            for(let j=0;j<n;j++){
                mtrx[i][j] = matrix[i][j]
            }
        }
        return mtrx;
    }

    //消元
    Elimination(matrix){
        let mtrx = this.copy(matrix);
        let n = mtrx.length;
        for(let k=1;k<n;k++){
            //选取k-1作为主 ，其他参照主消元 对角线 主元素 mtrx[m][m]
            let m = k-1;
            for(let i=k;i<n;i++){
                //系数 被消行 ，每个cell相乘用
                let factor = mtrx[i][m]/mtrx[m][m];
                for(let j=0;j<n;j++){
                    mtrx[m][j] = mtrx[m][j]*factor;
                    mtrx[i][j] = mtrx[i][j]-mtrx[m][j];
                }
            }
        }
        return mtrx;
    }

    //求逆矩阵 by  LU 分解
    InvByLU(matrix){
        let lu = this.LU(matrix);
        let invOfU = this.InvOfU(lu.U);
        let invOfL=  this.InvOfL(lu.L);
        return this.Mul(invOfU,invOfL);
    }

    //place 精确位数
    Round(matrix,place){
        let n = matrix.length;
        for(let i=0;i<n;i++){
            for(let j=0;j<n;j++){
                matrix[i][j] =  matrix[i][j].toFixed(place)-0;
            }
        }
        return matrix;
    }

}